﻿//----------------------------------------------------------------
// Desc: 
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2009-10-15
//
// Update Date :            
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


#define FUI_RT_MIN_HEAD_W 4


//----------------------------------------------------------------
// 报表排序状态
//----------------------------------------------------------------
enum EF_RT_SORT_STATE
{
    eRSS_NonSort,           // 未排过序
    eRSS_Lower,             // 降序
    eRSS_Ascend,            // 升序
};


class FUI_Report;


//----------------------------------------------------------------
// 报表头
//----------------------------------------------------------------
class FAPI FU_RT_HEAD
{
    FUI_DECLARE_STRUCT(FU_RT_HEAD);

    friend class FUI_Report;

public:
    FU_RT_HEAD()
    {}
    FU_RT_HEAD(const WCHAR* txt, int w, bool isnumber)
        :bySort(eRSS_NonSort)
        ,szText(txt)
        ,nWidth(w)
        ,bNumber(isnumber)
        ,bCanSize(true)
        ,nMinWidth(0)
    {}
    FU_RT_HEAD(const ACHAR* txt, int w, bool isnumber)
        :bySort(eRSS_NonSort)
        ,szText(txt)
        ,nWidth(w)
        ,bNumber(isnumber)
        ,bCanSize(true)
        ,nMinWidth(0)
    {}
    virtual~FU_RT_HEAD()
    {}
    FINLINE EF_RT_SORT_STATE GetSortState(){ return bySort; }

protected:
    EF_RT_SORT_STATE bySort;// 排序状态
    bool bNumber;           // 此列的数据类型是否是数字型
    int nWidth;             // 宽度
    int nIndex;             // 头索引

public:
    FUI_StringW szText;     // 显示文本
    BYTE bCanSize;          // 能否拖动大小
    int nMinWidth;          // 最小宽度（大于0表示以此值控件，否则以控件nMinHeadWidth为准）

    FINLINE int GetWidth(){ return nWidth; }
    FINLINE bool IsNumber(){ return bNumber; }
    FINLINE int GetIndex(){ return nIndex; }
};
typedef FUI_Vector< FU_RT_HEAD > FV_UI_RT_HEAD;


//----------------------------------------------------------------
// 报表的单项
//----------------------------------------------------------------
class FAPI FU_RT_ITEM
{
    FUI_DECLARE_STRUCT(FU_RT_ITEM);

    friend class FUI_Report;

public:
    FU_RT_ITEM(const WCHAR* txt)
        :nIndex(0)
        ,szText(txt)
        ,dwID(0)
        ,dwDataPtr(0)
        ,dwColor(0)
    {}
    virtual~FU_RT_ITEM()
    {}

protected:
    int nIndex;             // 在 vCellDataLib 中的索引

public:
    FUI_StringW szText;     // 显示文本
    DWORD dwColor;          // 项的文本颜色
    DWORD dwID;             // ID
    DWORD_PTR dwDataPtr;    // 用户数据

    FINLINE const WCHAR* GetText() { return szText.c_str();}
    FINLINE void SetText(const WCHAR* str) { szText = str;  }
    FINLINE void SetText(const ACHAR* str) { szText = str;  }
    FINLINE void Draw(FUI_Report* pCtrl, fuRect* rc, BYTE flags);
    FINLINE int GetIndex(){ return nIndex; }
};
typedef FUI_Vector< FU_RT_ITEM* > FV_UI_PRT_ITEM;


//----------------------------------------------------------------
// 报表的数据行
//----------------------------------------------------------------
class FAPI FU_RT_LINE
{
    FUI_DECLARE_STRUCT(FU_RT_LINE);

    friend class FUI_Report;

public:
    FU_RT_LINE()
        :nIndex(0)
        ,bSelect(false)
        ,bSuspend(false)
    {}

protected:
    FV_UI_PRT_ITEM vpLineAddr; // 是引用，不是NEW出来的
    int nIndex;         // 在行中的索引
    bool bSelect;       // 当前是否是选中项
    bool bSuspend;      // 当前是否是悬停项

public:
    FINLINE FU_RT_ITEM* GetItem(int index){ return vpLineAddr[index]; }
    FINLINE int GetIndex(){ return nIndex; }
    FINLINE int GetCount(){ return (int)vpLineAddr.size(); }
    FINLINE bool IsSelect(){ return bSelect; }
    FINLINE bool IsSuspend(){ return bSuspend; }
    FINLINE void SetLineTextCol(DWORD dwColor)
    { 
        for (size_t n = 0; n < vpLineAddr.size(); n++)
            vpLineAddr[n]->dwColor = dwColor;
    }
};
typedef FUI_Vector< FU_RT_LINE > FV_UI_RT_LINE;


//----------------------------------------------------------------
//
//----------------------------------------------------------------
class FUI_Report;
typedef void (*FUI_Report_Render_Head)(FUI_Report* pctrl, fuRect* rc, FU_RT_HEAD* phead, DWORD flags, bool non_text);
typedef void (*FUI_Report_Render_Item)(FUI_Report* pctrl, fuRect* rc, FU_RT_LINE* pline, int itemindex, DWORD flags, bool non_text);


//----------------------------------------------------------------
//
//----------------------------------------------------------------
class FAPI FUI_Report : public FUI_Object
{
    FUI_DECLARE_CLASS(FUI_Report)

protected:
    struct REPORT_SORT
    {
        FUI_StringW sztext;
        bool bNumber;
        int nNumber, nLineIndex;
		REPORT_SORT(){}
        REPORT_SORT(const WCHAR* txt, int index, bool isnumber);
        bool operator > (const REPORT_SORT& _right) const;
        bool operator < (const REPORT_SORT& _right) const;
    };
    typedef FUI_Vector< REPORT_SORT > FV_UI_REPORT_SORT;

public:
    FUI_Report(EF_UI_WIDGET_TYPE t = eUWT_Report);
    virtual void Release();
    virtual void Render(EF_UI_RENDER_LAYER layer);
    virtual void UpdateRect();
    virtual bool IsChild(FUI_Object* pChild);
    virtual bool HasClip(){ return !vHeadDataLib.empty(); }
    virtual void SetHeight(funit h);
    virtual bool OnKeyDown(unsigned int nChar);
    virtual bool OnMouseWheel(bool bUp, funit nX, funit nY);
    virtual bool OnMouseMove(funit nX, funit nY);
    virtual bool OnLButtonDown(funit nX, funit nY);
    virtual bool OnLButtonUp(funit nX, funit nY);
    virtual void OnFrameHide(bool visable);

    // 初始化表头（注意表头宽度不能太小）
    bool InitHead(FV_UI_RT_HEAD& vHeadInfo);
    // 插入行
    FU_RT_LINE* InsertLine(FUI_VStringW& vLineInfo, int index = -1);
    FU_RT_LINE* InsertLine(FUI_VStringA& vLineInfo, int index = -1);
    // 删除行
    void DeleteLine(int index);
    // 排序报表
    void SortByHead(int index, bool uselower);
    // 选中某项
    FU_RT_LINE* SetSelectByIndex(int index);
    // 报表数据交换
    bool Exchange(int srcIndex, int dstIndex);
    // 清空
    void Clear(bool with_head = false);
    // item_count 偏移多少项
    void ModifyScrollBar(int item_count);
    // 获得某一列的宽度
    int GetTierWidth(int nTierIndex);
    // 设置某行颜色，或者整体
    void SetLineFontColor(DWORD dwColor, int nIndex = -1);
    // 获取鼠标所在行
    FU_RT_LINE* GetMouseAtline(funit nX, funit nY);
    // 设置某列的宽度
    void SetHeadWidth(int idx, int width);
    // 刷新头列表宽度
    void RefHeadWidth(bool send_msg, int idx);

    // 获取行数据
    FINLINE FU_RT_LINE* GetLine(int index){ assert(index >= 0 && index < (int)vLineDataLb.size()); return &vLineDataLb[index]; }
    // 获取头的项数量
    FINLINE int GetHeadCount(){ return (int)vHeadDataLib.size(); }
    // 获取头数据
    FINLINE FU_RT_HEAD* GetHead(int idx){ if (idx >= 0 && idx < (int)vHeadDataLib.size()) return &vHeadDataLib[idx]; return 0; }
    // 取得数据行数
    FINLINE int Count(){ return (int)vLineDataLb.size(); }
    // 设置行高，不影响已修改的行高项
    FINLINE void SetLineHeight(WORD height){ pReportData->nLineHeight = height;}
    // 获取默认行高
    FINLINE int GetLineHeight(){ return pReportData->nLineHeight; }
    // 当前选中行
    FINLINE FU_RT_LINE* GetSelect(){ return pSelectLine; }
    FINLINE FU_RT_LINE* GetSuspend(){ return pSuspendLine; }
    // 设置自定义绘制函数
    FINLINE void SetRenderHeadFunc(FUI_Report_Render_Head pfunc){ pRTRenderHead = pfunc; }
    FINLINE void SetRenderItemFunc(FUI_Report_Render_Item pfunc){ pRTRenderItem = pfunc; }
    // 设置头信息
    FINLINE void SetHideHead(bool hide){ pReportData->SetHideHead(hide);   }
    FINLINE void SetHeadFull(bool full){ pReportData->SetHeadFullRowDraw(full); }
    // 获取横向滑块数据
    FINLINE int GetHScrollbarMax(){ UpdateRect(); int n = nHeadCountWidth - (int)uWorkRect.uSize.nW; if (n > 0) return n; return 0; }
    // 设置横向滑块的显示位置
    FINLINE void SetHscrollbarValue(int n){ nHScrollbarPos = n; if (nHScrollbarPos < 0) nHScrollbarPos = 0; }
    // 设置最小表示宽度
    FINLINE void SetMinHeadWidth(int w){ nMinHeadWidth = w; if (nMinHeadWidth < FUI_RT_MIN_HEAD_W) nMinHeadWidth = FUI_RT_MIN_HEAD_W; }
    // 获取部分控件数据
    FINLINE FUI_ScrollBar& GetScroll(){ return uScrollBar; }

protected:
    virtual void InitUIData(FUI_Object* father, fuWidgetBase* pData, FUI_Layout* layout);
    virtual void Update();

    void UpdateCellDataIndex();
    void UpdateLineIndex();
    void CancelSelect();
    void CancelSuspend();
    int GetItemOffsetY(int index);
    void RenderReport(bool text);
    void RenderHead(fuRect& headrect, FU_RT_HEAD& pHead, fuRect& workrect, bool text);
    void RenderLineState(fuRect& linerect, FU_RT_LINE& pLine, fuRect& workrect);
    void RenderLineItem(fuRect& itemrect, FU_RT_LINE* pLine, size_t index, fuRect& workrect, bool text);

protected:
    fuWidgetReport* pReportData;        // 控件数据地址
    FUI_ScrollBar uScrollBar;           // 
    int nMinHeadWidth;                  // 最小允许单个表头宽度
    int nHeadCountWidth;                // 所有的头加起来的宽度
    FV_UI_RT_HEAD  vHeadDataLib;        // 头数据库，是实体
    FV_UI_PRT_ITEM vCellDataLib;        // 单元数据库，是FUI_New出来的
    FV_UI_RT_LINE  vLineDataLb;         // 行数据库，是实体    
    FU_RT_LINE* pSelectLine;            // 当前选中行
    FU_RT_LINE* pSuspendLine;           // 当前悬停行
    int nHScrollbarPos;                 // 横向滚动条的显示位置
    FUI_Report_Render_Head pRTRenderHead;// 自定义项绘制头函数
    FUI_Report_Render_Item pRTRenderItem;// 自定义项绘制项函数
    fuPoint uDragHeadStart;             // 拖动列宽时启动坐标
    int nDragHeadIdx;                   // 拖动列宽时的目标列（-1无效）
};


FINLINE void FU_RT_ITEM::Draw(FUI_Report* pCtrl, fuRect* rc, BYTE flags)
{
    if (dwColor != 0)
        pCtrl->DrawString(rc, szText.c_str(), dwColor, flags);
    else
        pCtrl->DrawString(rc, szText.c_str(), flags);
}
